<?php

abstract class Quad_Scrub {
	
	public static $loggerClass;
	
	public static $scrubTypes = array(
		'word'         => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}\d -\/:;=\?@\[-_\{-~\r\n\t\.]/u',
		'words'        => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}\d -\/:;=\?@\[-_\{-~\r\n\t\.]/u',
		'bool'         => '/^(false|f|0|no|n)$/i',
		'alpha'        => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}]/u',
		'letter'       => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}]/u',
		'letters'      => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}]/u',
		'alphanum'     => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}\d]/u',
		'alphanumeric' => '/[^a-zA-Z\x{00C0}-\x{00FF}\x{0100}-\x{02AF}\x{1E00}-\x{1EF9}\d]/u',
		'isodate'      => '/[^\d :TzZ-]/',
		'email'        => "/[^@\w\.!#$%&'*+\-\/=?^_`{|}~]/", // http://en.wikipedia.org/wiki/E-mail_address Dec 2009
		'url'          => '/[^\w\._&?#+%=\/~:-]/',
		'ascii'        => '/[^ -~]/',
		'numeric'      => '/[^\d\.-]/',
		'number'       => '/[^\d\.-]/',
		'num'          => '/[^\d\.-]/',
		'int'          => '/[^\d\.-]/',
		'float'        => '/[^\de\.-]/',
	);
	
	public static function clean(&$input, $type = 'word', $securityCheck = false) {
		// input should be a list
		if (substr($type,-2) == '[]') {
			$type = substr($type, 0, -2);
			if (is_array($input)) {
				foreach ($input as &$data) {
					self::clean($data, $type, $securityCheck);
				}
			}
			else {
				$input = array();
			}
			return $input;
		}
		// input should be a scalar value
		if (is_array($type)) {
			// restrict to one of given values
			$value = (in_array($input, $type) ? $input : '');
		}
		elseif (is_object($type) && is_callable(array($type, 'matches'))) {
			// raw regex given
			$value = ($type->matches($input) ? $value : null);
		}
		elseif ($type == 'bool') {
			$value = (bool) preg_replace(self::$scrubTypes['bool'], '', $input);
		}
		else {
			// restrict to one of self::$scrubTypes
			$type = strtolower($type);
			if (isset(self::$scrubTypes[$type])) {
				$value = preg_replace(self::$scrubTypes[$type], '', $input);
			}
			// or use a regular expression if needed
			elseif (preg_match('/^\W.+\W[imsxeADSUXJu]*$/', $type)) {
				$value = (@preg_match($type, $input) ? $input : '');
			}
			switch ($type) {
				case 'int':   $value = (int) $value;   break;
				case 'float': $value = (float) $value; break;
			}
		}
		if ($securityCheck && $value != $input) {
			// log security warning if data was invalid and security check is enabled
			$data = $input;
			self::maxlen($data, 900);
			$msg = "Quad_Scrub security warning: scrubber `$type` received bad data: `$data`";
			$ok = false;
			// use logger class if set
			if (self::$loggerClass) {
				$logger = new self::$loggerClass;
				$ok = $logger->append($msg);
				unset($logger);
			}
			// if we have no logger class or logger class fails, log to php error log
			if (!$ok) {
				trigger_error($msg, 'E_USER_WARNING');
			}
		}	
		$input = $value;
		return $input;
	}
	
	public static function maxlen(&$value, $max) {
		if (version_compare(PHP_VERSION, '6.0.0', '>=')) {
			$value = substr($value, 0, $max);
			
		} elseif (function_exists('mb_substr')) {
			$value = mb_substr($value, 0, $max);
			
		} else {
			$max = (int) $max;
			$value = preg_replace("/^(.{0,$max}).*/s", '$1', $value);
		}
		return $value;
	}	
	
	public static function esc($value) {
		$value = htmlentities($value, ENT_COMPAT, 'utf-8');
		return $value;
	}	
	
}